﻿/*
 * Alunos: Thiago Augusto Pavan Rocha e Duyle Ruan Gonçalves de Campos
 * Matrícula: 00912326 e 00911960
 **/
using System;
using System.IO;
using System.Net;
using System.Data;
using System.Text;
using System.Drawing;
using Chat = System.Net;
using System.Threading;
using System.Collections;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace PC {
    public partial class ChatClientForm : Form {

        public List<String> msgQueue = new List<String>();
        static Chat.Sockets.TcpClient tcpClient;
        static Thread lerFila;

        // Usado pra poder usar o evento "Closing"
        [DllImport("kernel32.dll")]
        private static extern void ExitProcess(int a);

        StreamReader sr = File.OpenText("config.ini");
        public string ServerIP;
        public string ServerPort;
        public static string BackGroundColor;

        public ChatClientForm() {
            InitializeComponent();
            this.Closing += new CancelEventHandler(ChatClient_Closing);
            this.txtMensagem.KeyUp += new KeyEventHandler(key_up);

            tcpClient = new Chat.Sockets.TcpClient();

            // Mostra a tela de escolha de nickname e realiza a conexão...
            this.getConfig();
            showNickName();

            // Thread responsável por ler a fila.
            lerFila = new Thread(new ThreadStart(readQueue));
            lerFila.Name = "Ler Fila";
            lerFila.Start();

            // Thread responsável pela comunicação com o servidor.
            Thread chatThread = new Thread(new ThreadStart(run));
            chatThread.Start();
            while (true) {
                Application.DoEvents();
            }

        }

        private void showNickName() {
            Usuario.nome = Usuario.ip = Usuario.config = null;
            NicknameForm nickname = new NicknameForm();
            nickname.ShowDialog();
            this.Show();
            try {
                if (tcpClient.Connected == false) {
                    tcpClient.Connect(IPAddress.Parse(this.ServerIP), Convert.ToInt32(this.ServerPort));
                }
                StreamWriter writer = new StreamWriter(tcpClient.GetStream());
                writer.WriteLine(Usuario.nome);
                writer.Flush();
                this.Text += " - " + Usuario.nome;
            } catch (Exception ex) {
                MessageBox.Show("Não foi possível se conectar com o servidor.");
                ExitProcess(0);
            }
        }

        // quando o usuário fechar o chat...
        private static void ChatClient_Closing(object s, CancelEventArgs e) {
            /** Envia a cor do plano de fundo atual para o servidor **/            
            StreamWriter writer = new StreamWriter(tcpClient.GetStream());
            e.Cancel = false;
            writer.WriteLine("flag|saiu|" + Usuario.nome);
            writer.Flush();
            Application.Exit();
            ExitProcess(0);
        }

        private void key_up(object s, KeyEventArgs e) {
            if (this.txtMensagem.Lines.Length > 1) {
                StreamWriter writer = new StreamWriter(tcpClient.GetStream());
                if (chkMensagemPrivada.Checked == false) {
                    writer.WriteLine(this.txtMensagem.Text);
                    writer.Flush();
                } else {
                    if (lstListaNomes.SelectedIndex != -1) {
                        writer.WriteLine("flag|private_msg|" + lstListaNomes.SelectedItem + "|" + this.txtMensagem.Text);
                        writer.Flush();
                    } else {
                        MessageBox.Show("Por favor, selecione algum usuário da lista.", "Aviso");
                    }
                }
                this.txtMensagem.Text = "";
                this.txtMensagem.Lines = null;
            }
        }

        private void run() {
            string msgRecebida = "";
            string[] flag;
            StreamReader reader = new StreamReader(tcpClient.GetStream());
            while (true) {
                try {
                    Application.DoEvents();
                    msgRecebida = reader.ReadLine();
                    // Caso seja uma mensagem com flags
                    if (msgRecebida.Contains("flag|")) {
                        flag = msgRecebida.Split('|');
                        switch (flag[1]) {
                            case "nickname_duplicado":
                                MessageBox.Show("Este nome já está em uso, por favor escolha outro.", "Aviso");
                                showNickName();
                                break;

                            case "lista_usuarios":
                                lstListaNomes.Items.Clear();
                                for (int i = 2; i < flag.Length; i++) {
                                    lstListaNomes.Items.Add(flag[i]);
                                }
                                break;
                            case "configuration":
                                BackGroundColor = flag[2]; 
                                ChangeBackground();
                                break;
                            case "fila_off":
                                string[] temp;
                                temp = flag[0].Split(':');
                                this.txtLog.AppendText(temp[0] + ": " + flag[2] + "\r\n");
                                this.txtLog.SelectionStart = this.txtLog.Text.Length;
                                if (this != Form.ActiveForm)
                                    FlashWindow.Flash(this);
                                break;
                            default:
                                this.msgQueue.Add(msgRecebida);
                                break;
                        }
                        // Caso seja uma mensagem normal
                    } else {
                        this.msgQueue.Add(msgRecebida);
                    }
                } catch (Exception e) {
                    MessageBox.Show("O servidor parou de responder... ", "Aviso");
                    ExitProcess(0);
                }
            }
        }

        // Thread responsável para ficar lendo a fila e imprimindo as mensagens na tela.
        public void readQueue() {
            string msg = "";
            while (true) {
                if (msgQueue.Count > 0) {
                    Console.WriteLine("ping :)");
                    for (int i = 0; i < msgQueue.Count; i++) {
                        msg = msgQueue[i];
                        this.txtLog.AppendText(msg + "\r\n");
                        this.txtLog.SelectionStart = this.txtLog.Text.Length;
                        if (this != Form.ActiveForm)
                            FlashWindow.Flash(this);
                    }
                    msgQueue.Clear();
                }
                System.Threading.Thread.Sleep(250);
            }
        }

        /********************************************************************************/
        /********** Função utilizada para pegar configurações de IP e PORTA *************/
        /********************************************************************************/
        private void getConfig() {
            String FileContent = "";
            while (FileContent != "END") {
                FileContent = this.sr.ReadLine();
                if (FileContent.IndexOf("ServerIP") != -1) {
                    this.ServerIP = FileContent.Substring(FileContent.IndexOf("=") + 1).Trim();
                } else if (FileContent.IndexOf("ServerPort") != -1) {
                    this.ServerPort = FileContent.Substring(FileContent.IndexOf("=") + 1).Trim();
                }
            }
        }


        public void ChangeBackground() {
            try {
                Color color = System.Drawing.ColorTranslator.FromHtml(BackGroundColor);
                ChatClientForm.ActiveForm.BackColor = color;
                saveConfigurations();
            } catch {
                MessageBox.Show("Digite uma cor em formato hexadecimal.\nEx: #FFEEDD");
            }
        }

        public static void saveConfigurations() {
            StreamWriter writer = new StreamWriter(tcpClient.GetStream());
            writer.WriteLine("flag|configuration|" + BackGroundColor);
            writer.Flush();
        }

        private void btnAplicarBg_Click(object sender, EventArgs e)
        {
            BackGroundColor = txtBackColor.Text;
            this.ChangeBackground();
        }
    }
}